/*
 * Copyright (c) 2022 xjunz. All rights reserved.
 */

package top.xjunz.tasker.engine.applet.base

import top.xjunz.tasker.engine.runtime.TaskRuntime

/**
 * A [ScopeFlow] initializes its target at [Flow.onPrepareApply]. The target will be used by all of its
 * elements.
 *
 * @author xjunz 2022/12/04
 */
abstract class ScopeFlow<Target : Any> : Flow() {

    /**
     * Generate the overall target. The result will be registered to the snapshot in runtime
     * and can be accessed across tasks with a key. This is done in [onPrepareApply].
     */
    abstract fun initializeTarget(runtime: TaskRuntime): Target

    /**
     * Get the initialized target, which is generated by [initializeTarget].
     */
    protected inline val TaskRuntime.target: Target get() = getTarget()

    /**
     * By default, the target is stored with [id] as the key. If you want to store more
     * variables, you can call this to generate a unique key without conflict with other
     * potential keys.
     */
    fun generateUniqueKey(seed: Int): Long {
        return seed.toLong() shl Int.SIZE_BITS or id.toLong()
    }

    override fun onPrepareApply(runtime: TaskRuntime) {
        super.onPrepareApply(runtime)
        runtime.setTarget(
            runtime.getScopedValue(TaskRuntime.GLOBAL_SCOPE_TASK, id) {
                initializeTarget(runtime)
            }
        )
    }
}